# Load in libraries
library(beeswarm)
library(naniar)
library(zoo)
library(janitor)
library(dplyr)
library(plyr)
library(tidyverse)
library(ggplot2)
library(GGally) # for ggpairs
library(lubridate)
# Load in data (only care about census to cluster on)
cases_plus_census <- read_csv("./../project_1/data/COVID-19_cases_plus_census.csv")
── Column specification ──────────────────────────────────────────────────────────────────────────────────────────
cols(
.default = col_double(),
county_fips_code = col_character(),
county_name = col_character(),
state = col_character(),
state_fips_code = col_character(),
date = col_date(format = ""),
geo_id = col_character(),
pop_5_years_over = col_logical(),
speak_only_english_at_home = col_logical(),
speak_spanish_at_home = col_logical(),
speak_spanish_at_home_low_english = col_logical(),
pop_15_and_over = col_logical(),
pop_never_married = col_logical(),
pop_now_married = col_logical(),
pop_separated = col_logical(),
pop_widowed = col_logical(),
pop_divorced = col_logical()
)
ℹ Use `spec()` for the full column specifications.
cases_plus_census
# Add in the attributes we want to use
cols_keep <- c("county_fips_code", "county_name", "state", "confirmed_cases", "deaths", "median_income", "male_pop", "female_pop", "total_pop", "median_age", "worked_at_home", "male_65_to_66", "male_67_to_69",
"male_70_to_74", "male_75_to_79", "male_80_to_84",
"male_85_and_over", "female_65_to_66", "female_67_to_69",
"female_70_to_74", "female_75_to_79", "female_80_to_84",
"female_85_and_over")
subset_census <- cases_plus_census[cols_keep]
subset_census$male_elderly_pop <- subset_census %>% select(c("male_65_to_66",
"male_67_to_69",
"male_70_to_74",
"male_75_to_79",
"male_80_to_84",
"male_85_and_over")
) %>% rowSums()
subset_census$female_elderly_pop <- subset_census %>% select(c("female_65_to_66",
"female_67_to_69",
"female_70_to_74",
"female_75_to_79",
"female_80_to_84",
"female_85_and_over")
) %>% rowSums()
cols_keep <- c("county_fips_code", "county_name", "state", "confirmed_cases", "deaths", "median_income",
"male_pop", "female_pop", "total_pop", "median_age",
"worked_at_home", "male_elderly_pop", "female_elderly_pop")
subset_census <- subset_census[cols_keep]
subset_census <- subset_census %>%
mutate(county_fips_code = as.integer(county_fips_code)) %>%
mutate(state = as.factor(state))
columnNames <- colnames(subset_census)
keep_cols <- columnNames[!columnNames %in% c("county_fips_code", "county_name")]
# Aggregate by states (probably better way to do this but had issues with mean median income)
mm_income <- subset_census %>% select(keep_cols) %>% group_by(state) %>%
summarise_at(c("median_income", "median_age"), mean) %>% ungroup() %>%
dplyr::rename(mean_median_income = median_income) %>%
dplyr::rename(mean_median_age = median_age)
keep_cols <- columnNames[!columnNames %in% c("county_fips_code", "county_name", "median_income", "median_age")]
agg_state_info <- subset_census %>% select(keep_cols) %>% group_by(state) %>%
summarize_if(is.numeric, sum) %>% ungroup() %>%
left_join(mm_income, by="state")
# Aggregated state information (not normalized!)
agg_state_info
# To be able to compare properly, convert to percentages for aggregated population stats
# Infections/deaths
subset_census$pct_infected <- subset_census$confirmed_cases/subset_census$total_pop
subset_census$pct_deaths <- subset_census$deaths/subset_census$total_pop
subset_census$mortality_rate <- subset_census$deaths/subset_census$confirmed_cases
# Male/female info
subset_census$pct_male_population <- subset_census$male_pop/subset_census$total_pop
subset_census$pct_female_population <- subset_census$female_pop/subset_census$total_pop
# Intermediate calculation
subset_census$elderly_pop <- subset_census$male_elderly_pop + subset_census$female_elderly_pop
# Elderly Info
subset_census$pct_elderly <- subset_census$elderly_pop/subset_census$total_pop
subset_census$pct_male_elderly <- subset_census$male_elderly_pop/subset_census$total_pop
subset_census$pct_female_elderly <- subset_census$female_elderly_pop/subset_census$total_pop
# Work from home
subset_census$pct_worked_at_home <- subset_census$worked_at_home/subset_census$total_pop
# Only keep newly made values
cols_keep <- c("county_fips_code", "county_name", "state", "pct_infected",
"pct_deaths", "mortality_rate", "pct_elderly", "pct_male_elderly",
"pct_female_elderly", "pct_male_population",
"pct_female_population", "pct_worked_at_home",
"median_income", "median_age")
subset_census <- subset_census[cols_keep]
subset_census
# Percentages for state specific data
# Infections/deaths
agg_state_info$pct_infected <- agg_state_info$confirmed_cases/agg_state_info$total_pop
agg_state_info$pct_deaths <- agg_state_info$deaths/agg_state_info$total_pop
agg_state_info$mortality_rate <- agg_state_info$deaths/agg_state_info$confirmed_cases
# Male/female info
agg_state_info$pct_male_population <- agg_state_info$male_pop/agg_state_info$total_pop
agg_state_info$pct_female_population <- agg_state_info$female_pop/agg_state_info$total_pop
# Intermediate calculation
agg_state_info$elderly_pop <- agg_state_info$male_elderly_pop + agg_state_info$female_elderly_pop
# Elderly Info
agg_state_info$pct_elderly <- agg_state_info$elderly_pop/agg_state_info$total_pop
agg_state_info$pct_male_elderly <- agg_state_info$male_elderly_pop/agg_state_info$total_pop
agg_state_info$pct_female_elderly <- agg_state_info$female_elderly_pop/agg_state_info$total_pop
# Work from home
agg_state_info$pct_worked_at_home <- agg_state_info$worked_at_home/agg_state_info$total_pop
# Only keep newly made values
cols_keep <- c("state", "pct_infected", "pct_deaths", "mortality_rate",
"pct_elderly", "pct_male_elderly", "pct_female_elderly",
"pct_male_population", "pct_female_population",
"pct_worked_at_home", "mean_median_income", "mean_median_age")
agg_state_info <- agg_state_info[cols_keep]
agg_state_info
# Normalized attributes function
scale_numeric <- function(x) x %>% mutate_if(is.double, function(y) as.vector(scale(y)))
# Normalized full census data (with mean and std based on counties from all of U.S.)
census_normed <- subset_census %>% scale_numeric()
# Normalized state info (with mean and std based on counties from all of U.S.)
agg_state_info_normed <- agg_state_info %>% scale_numeric()
# These are the ones to use for clustering
census_normed
agg_state_info_normed
# Saving to csv for better loading in other branches
write_csv(census_normed, "./../datasets/census_normed.csv")
write_csv(agg_state_info_normed, "./../datasets/agg_state_info_normed.csv")
# Example use to get TX specifically
ks = 2:4
WSS <- sapply(ks, FUN = function(k) {
kmeans(census_normed %>% filter(state=="TX")
%>% select_if(is.double), centers = k, nstart = 5)$tot.withinss
})
ggplot(as_tibble(ks, WSS), aes(ks, WSS)) + geom_line() +
geom_vline(xintercept = 4, color = "red", linetype = 2)
# Example using aggregated state data
ks = 2:4
WSS <- sapply(ks, FUN = function(k) {
kmeans(agg_state_info_normed %>% select_if(is.double),
centers = k, nstart = 5)$tot.withinss
})
ggplot(as_tibble(ks, WSS), aes(ks, WSS)) + geom_line() +
geom_vline(xintercept = 4, color = "red", linetype = 2)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyfQojIExvYWQgaW4gbGlicmFyaWVzIApsaWJyYXJ5KGJlZXN3YXJtKQpsaWJyYXJ5KG5hbmlhcikKbGlicmFyeSh6b28pCmxpYnJhcnkoamFuaXRvcikKbGlicmFyeShkcGx5cikKbGlicmFyeShwbHlyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KEdHYWxseSkgIyBmb3IgZ2dwYWlycwpsaWJyYXJ5KGx1YnJpZGF0ZSkKYGBgCgpgYGB7cn0KIyBMb2FkIGluIGRhdGEgKG9ubHkgY2FyZSBhYm91dCBjZW5zdXMgdG8gY2x1c3RlciBvbikKY2FzZXNfcGx1c19jZW5zdXMgPC0gcmVhZF9jc3YoIi4vLi4vcHJvamVjdF8xL2RhdGEvQ09WSUQtMTlfY2FzZXNfcGx1c19jZW5zdXMuY3N2IikKY2FzZXNfcGx1c19jZW5zdXMKYGBgCgpgYGB7cn0KIyBBZGQgaW4gdGhlIGF0dHJpYnV0ZXMgd2Ugd2FudCB0byB1c2UKY29sc19rZWVwIDwtIGMoImNvdW50eV9maXBzX2NvZGUiLCAiY291bnR5X25hbWUiLCAic3RhdGUiLCAiY29uZmlybWVkX2Nhc2VzIiwgImRlYXRocyIsICJtZWRpYW5faW5jb21lIiwgIm1hbGVfcG9wIiwgImZlbWFsZV9wb3AiLCAidG90YWxfcG9wIiwgIm1lZGlhbl9hZ2UiLCAid29ya2VkX2F0X2hvbWUiLCAibWFsZV82NV90b182NiIsICJtYWxlXzY3X3RvXzY5IiwgCiAgICAgICAgICAgICAgICJtYWxlXzcwX3RvXzc0IiwgIm1hbGVfNzVfdG9fNzkiLCAibWFsZV84MF90b184NCIsCiAgICAgICAgICAgICAgICJtYWxlXzg1X2FuZF9vdmVyIiwgImZlbWFsZV82NV90b182NiIsICJmZW1hbGVfNjdfdG9fNjkiLCAKICAgICAgICAgICAgICAgImZlbWFsZV83MF90b183NCIsICJmZW1hbGVfNzVfdG9fNzkiLCAiZmVtYWxlXzgwX3RvXzg0IiwKICAgICAgICAgICAgICAgImZlbWFsZV84NV9hbmRfb3ZlciIpCnN1YnNldF9jZW5zdXMgPC0gY2FzZXNfcGx1c19jZW5zdXNbY29sc19rZWVwXQoKc3Vic2V0X2NlbnN1cyRtYWxlX2VsZGVybHlfcG9wIDwtIHN1YnNldF9jZW5zdXMgJT4lIHNlbGVjdChjKCJtYWxlXzY1X3RvXzY2IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtYWxlXzY3X3RvXzY5IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibWFsZV83MF90b183NCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibWFsZV83NV90b183OSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibWFsZV84MF90b184NCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibWFsZV84NV9hbmRfb3ZlciIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgcm93U3VtcygpCgpzdWJzZXRfY2Vuc3VzJGZlbWFsZV9lbGRlcmx5X3BvcCA8LSBzdWJzZXRfY2Vuc3VzICU+JSBzZWxlY3QoYygiZmVtYWxlXzY1X3RvXzY2IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJmZW1hbGVfNjdfdG9fNjkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJmZW1hbGVfNzBfdG9fNzQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImZlbWFsZV83NV90b183OSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZmVtYWxlXzgwX3RvXzg0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJmZW1hbGVfODVfYW5kX292ZXIiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIHJvd1N1bXMoKQoKCmNvbHNfa2VlcCA8LSBjKCJjb3VudHlfZmlwc19jb2RlIiwgImNvdW50eV9uYW1lIiwgInN0YXRlIiwgImNvbmZpcm1lZF9jYXNlcyIsICJkZWF0aHMiLCAibWVkaWFuX2luY29tZSIsCiAgICAgICAgICAgICAgICJtYWxlX3BvcCIsICJmZW1hbGVfcG9wIiwgInRvdGFsX3BvcCIsICJtZWRpYW5fYWdlIiwKICAgICAgICAgICAgICAgIndvcmtlZF9hdF9ob21lIiwgIm1hbGVfZWxkZXJseV9wb3AiLCAiZmVtYWxlX2VsZGVybHlfcG9wIikKCnN1YnNldF9jZW5zdXMgPC0gc3Vic2V0X2NlbnN1c1tjb2xzX2tlZXBdCnN1YnNldF9jZW5zdXMgPC0gc3Vic2V0X2NlbnN1cyAlPiUgCiAgbXV0YXRlKGNvdW50eV9maXBzX2NvZGUgPSBhcy5pbnRlZ2VyKGNvdW50eV9maXBzX2NvZGUpKSAlPiUKICBtdXRhdGUoc3RhdGUgPSBhcy5mYWN0b3Ioc3RhdGUpKQpgYGAKYGBge3J9Cgpjb2x1bW5OYW1lcyA8LSBjb2xuYW1lcyhzdWJzZXRfY2Vuc3VzKQprZWVwX2NvbHMgPC0gY29sdW1uTmFtZXNbIWNvbHVtbk5hbWVzICVpbiUgYygiY291bnR5X2ZpcHNfY29kZSIsICJjb3VudHlfbmFtZSIpXQoKIyBBZ2dyZWdhdGUgYnkgc3RhdGVzIChwcm9iYWJseSBiZXR0ZXIgd2F5IHRvIGRvIHRoaXMgYnV0IGhhZCBpc3N1ZXMgd2l0aCBtZWFuIG1lZGlhbiBpbmNvbWUpCm1tX2luY29tZSA8LSBzdWJzZXRfY2Vuc3VzICU+JSBzZWxlY3Qoa2VlcF9jb2xzKSAlPiUgZ3JvdXBfYnkoc3RhdGUpICU+JQogIHN1bW1hcmlzZV9hdChjKCJtZWRpYW5faW5jb21lIiwgIm1lZGlhbl9hZ2UiKSwgbWVhbikgJT4lIHVuZ3JvdXAoKSAlPiUgCiAgZHBseXI6OnJlbmFtZShtZWFuX21lZGlhbl9pbmNvbWUgPSBtZWRpYW5faW5jb21lKSAlPiUgCiAgZHBseXI6OnJlbmFtZShtZWFuX21lZGlhbl9hZ2UgPSBtZWRpYW5fYWdlKQoKa2VlcF9jb2xzIDwtIGNvbHVtbk5hbWVzWyFjb2x1bW5OYW1lcyAlaW4lIGMoImNvdW50eV9maXBzX2NvZGUiLCAiY291bnR5X25hbWUiLCAibWVkaWFuX2luY29tZSIsICJtZWRpYW5fYWdlIildCmFnZ19zdGF0ZV9pbmZvIDwtIHN1YnNldF9jZW5zdXMgJT4lIHNlbGVjdChrZWVwX2NvbHMpICU+JSBncm91cF9ieShzdGF0ZSkgJT4lCiAgc3VtbWFyaXplX2lmKGlzLm51bWVyaWMsIHN1bSkgJT4lIHVuZ3JvdXAoKSAlPiUgCiAgbGVmdF9qb2luKG1tX2luY29tZSwgYnk9InN0YXRlIikKIAojIEFnZ3JlZ2F0ZWQgc3RhdGUgaW5mb3JtYXRpb24gKG5vdCBub3JtYWxpemVkISkKYWdnX3N0YXRlX2luZm8KYGBgCmBgYHtyfQojIFRvIGJlIGFibGUgdG8gY29tcGFyZSBwcm9wZXJseSwgY29udmVydCB0byBwZXJjZW50YWdlcyBmb3IgYWdncmVnYXRlZCBwb3B1bGF0aW9uIHN0YXRzCgojIEluZmVjdGlvbnMvZGVhdGhzCnN1YnNldF9jZW5zdXMkcGN0X2luZmVjdGVkIDwtIHN1YnNldF9jZW5zdXMkY29uZmlybWVkX2Nhc2VzL3N1YnNldF9jZW5zdXMkdG90YWxfcG9wCnN1YnNldF9jZW5zdXMkcGN0X2RlYXRocyA8LSBzdWJzZXRfY2Vuc3VzJGRlYXRocy9zdWJzZXRfY2Vuc3VzJHRvdGFsX3BvcApzdWJzZXRfY2Vuc3VzJG1vcnRhbGl0eV9yYXRlIDwtIHN1YnNldF9jZW5zdXMkZGVhdGhzL3N1YnNldF9jZW5zdXMkY29uZmlybWVkX2Nhc2VzCgojIE1hbGUvZmVtYWxlIGluZm8Kc3Vic2V0X2NlbnN1cyRwY3RfbWFsZV9wb3B1bGF0aW9uIDwtIHN1YnNldF9jZW5zdXMkbWFsZV9wb3Avc3Vic2V0X2NlbnN1cyR0b3RhbF9wb3AKc3Vic2V0X2NlbnN1cyRwY3RfZmVtYWxlX3BvcHVsYXRpb24gPC0gc3Vic2V0X2NlbnN1cyRmZW1hbGVfcG9wL3N1YnNldF9jZW5zdXMkdG90YWxfcG9wCgojIEludGVybWVkaWF0ZSBjYWxjdWxhdGlvbgpzdWJzZXRfY2Vuc3VzJGVsZGVybHlfcG9wIDwtIHN1YnNldF9jZW5zdXMkbWFsZV9lbGRlcmx5X3BvcCArIHN1YnNldF9jZW5zdXMkZmVtYWxlX2VsZGVybHlfcG9wCgojIEVsZGVybHkgSW5mbwpzdWJzZXRfY2Vuc3VzJHBjdF9lbGRlcmx5IDwtIHN1YnNldF9jZW5zdXMkZWxkZXJseV9wb3Avc3Vic2V0X2NlbnN1cyR0b3RhbF9wb3AKc3Vic2V0X2NlbnN1cyRwY3RfbWFsZV9lbGRlcmx5IDwtIHN1YnNldF9jZW5zdXMkbWFsZV9lbGRlcmx5X3BvcC9zdWJzZXRfY2Vuc3VzJHRvdGFsX3BvcApzdWJzZXRfY2Vuc3VzJHBjdF9mZW1hbGVfZWxkZXJseSA8LSBzdWJzZXRfY2Vuc3VzJGZlbWFsZV9lbGRlcmx5X3BvcC9zdWJzZXRfY2Vuc3VzJHRvdGFsX3BvcAoKIyBXb3JrIGZyb20gaG9tZQpzdWJzZXRfY2Vuc3VzJHBjdF93b3JrZWRfYXRfaG9tZSA8LSBzdWJzZXRfY2Vuc3VzJHdvcmtlZF9hdF9ob21lL3N1YnNldF9jZW5zdXMkdG90YWxfcG9wCgojIE9ubHkga2VlcCBuZXdseSBtYWRlIHZhbHVlcwpjb2xzX2tlZXAgPC0gYygiY291bnR5X2ZpcHNfY29kZSIsICJjb3VudHlfbmFtZSIsICJzdGF0ZSIsICJwY3RfaW5mZWN0ZWQiLAogICAgICAgICAgICAgICAicGN0X2RlYXRocyIsICJtb3J0YWxpdHlfcmF0ZSIsICJwY3RfZWxkZXJseSIsICJwY3RfbWFsZV9lbGRlcmx5IiwKICAgICAgICAgICAgICAgInBjdF9mZW1hbGVfZWxkZXJseSIsICJwY3RfbWFsZV9wb3B1bGF0aW9uIiwgCiAgICAgICAgICAgICAgICJwY3RfZmVtYWxlX3BvcHVsYXRpb24iLCAicGN0X3dvcmtlZF9hdF9ob21lIiwKICAgICAgICAgICAgICAgIm1lZGlhbl9pbmNvbWUiLCAibWVkaWFuX2FnZSIpCgoKc3Vic2V0X2NlbnN1cyA8LSBzdWJzZXRfY2Vuc3VzW2NvbHNfa2VlcF0Kc3Vic2V0X2NlbnN1cwpgYGAKYGBge3J9CiMgUGVyY2VudGFnZXMgZm9yIHN0YXRlIHNwZWNpZmljIGRhdGEKCiMgSW5mZWN0aW9ucy9kZWF0aHMKYWdnX3N0YXRlX2luZm8kcGN0X2luZmVjdGVkIDwtIGFnZ19zdGF0ZV9pbmZvJGNvbmZpcm1lZF9jYXNlcy9hZ2dfc3RhdGVfaW5mbyR0b3RhbF9wb3AKYWdnX3N0YXRlX2luZm8kcGN0X2RlYXRocyA8LSBhZ2dfc3RhdGVfaW5mbyRkZWF0aHMvYWdnX3N0YXRlX2luZm8kdG90YWxfcG9wCmFnZ19zdGF0ZV9pbmZvJG1vcnRhbGl0eV9yYXRlIDwtIGFnZ19zdGF0ZV9pbmZvJGRlYXRocy9hZ2dfc3RhdGVfaW5mbyRjb25maXJtZWRfY2FzZXMKCiMgTWFsZS9mZW1hbGUgaW5mbwphZ2dfc3RhdGVfaW5mbyRwY3RfbWFsZV9wb3B1bGF0aW9uIDwtIGFnZ19zdGF0ZV9pbmZvJG1hbGVfcG9wL2FnZ19zdGF0ZV9pbmZvJHRvdGFsX3BvcAphZ2dfc3RhdGVfaW5mbyRwY3RfZmVtYWxlX3BvcHVsYXRpb24gPC0gYWdnX3N0YXRlX2luZm8kZmVtYWxlX3BvcC9hZ2dfc3RhdGVfaW5mbyR0b3RhbF9wb3AKCiMgSW50ZXJtZWRpYXRlIGNhbGN1bGF0aW9uCmFnZ19zdGF0ZV9pbmZvJGVsZGVybHlfcG9wIDwtIGFnZ19zdGF0ZV9pbmZvJG1hbGVfZWxkZXJseV9wb3AgKyBhZ2dfc3RhdGVfaW5mbyRmZW1hbGVfZWxkZXJseV9wb3AKCiMgRWxkZXJseSBJbmZvCmFnZ19zdGF0ZV9pbmZvJHBjdF9lbGRlcmx5IDwtIGFnZ19zdGF0ZV9pbmZvJGVsZGVybHlfcG9wL2FnZ19zdGF0ZV9pbmZvJHRvdGFsX3BvcAphZ2dfc3RhdGVfaW5mbyRwY3RfbWFsZV9lbGRlcmx5IDwtIGFnZ19zdGF0ZV9pbmZvJG1hbGVfZWxkZXJseV9wb3AvYWdnX3N0YXRlX2luZm8kdG90YWxfcG9wCmFnZ19zdGF0ZV9pbmZvJHBjdF9mZW1hbGVfZWxkZXJseSA8LSBhZ2dfc3RhdGVfaW5mbyRmZW1hbGVfZWxkZXJseV9wb3AvYWdnX3N0YXRlX2luZm8kdG90YWxfcG9wCgojIFdvcmsgZnJvbSBob21lCmFnZ19zdGF0ZV9pbmZvJHBjdF93b3JrZWRfYXRfaG9tZSA8LSBhZ2dfc3RhdGVfaW5mbyR3b3JrZWRfYXRfaG9tZS9hZ2dfc3RhdGVfaW5mbyR0b3RhbF9wb3AKCiMgT25seSBrZWVwIG5ld2x5IG1hZGUgdmFsdWVzCmNvbHNfa2VlcCA8LSBjKCJzdGF0ZSIsICJwY3RfaW5mZWN0ZWQiLCAicGN0X2RlYXRocyIsICJtb3J0YWxpdHlfcmF0ZSIsIAogICAgICAgICAgICAgICAicGN0X2VsZGVybHkiLCAicGN0X21hbGVfZWxkZXJseSIsICJwY3RfZmVtYWxlX2VsZGVybHkiLCAKICAgICAgICAgICAgICAgInBjdF9tYWxlX3BvcHVsYXRpb24iLCAicGN0X2ZlbWFsZV9wb3B1bGF0aW9uIiwgCiAgICAgICAgICAgICAgICJwY3Rfd29ya2VkX2F0X2hvbWUiLCAibWVhbl9tZWRpYW5faW5jb21lIiwgIm1lYW5fbWVkaWFuX2FnZSIpCgoKYWdnX3N0YXRlX2luZm8gPC0gYWdnX3N0YXRlX2luZm9bY29sc19rZWVwXQphZ2dfc3RhdGVfaW5mbwpgYGAKCgpgYGB7cn0KIyBOb3JtYWxpemVkIGF0dHJpYnV0ZXMgZnVuY3Rpb24Kc2NhbGVfbnVtZXJpYyA8LSBmdW5jdGlvbih4KSB4ICU+JSBtdXRhdGVfaWYoaXMuZG91YmxlLCBmdW5jdGlvbih5KSBhcy52ZWN0b3Ioc2NhbGUoeSkpKQoKIyBOb3JtYWxpemVkIGZ1bGwgY2Vuc3VzIGRhdGEgKHdpdGggbWVhbiBhbmQgc3RkIGJhc2VkIG9uIGNvdW50aWVzIGZyb20gYWxsIG9mIFUuUy4pCmNlbnN1c19ub3JtZWQgPC0gc3Vic2V0X2NlbnN1cyAlPiUgc2NhbGVfbnVtZXJpYygpCgojIE5vcm1hbGl6ZWQgc3RhdGUgaW5mbyAod2l0aCBtZWFuIGFuZCBzdGQgYmFzZWQgb24gY291bnRpZXMgZnJvbSBhbGwgb2YgVS5TLikKYWdnX3N0YXRlX2luZm9fbm9ybWVkIDwtIGFnZ19zdGF0ZV9pbmZvICU+JSBzY2FsZV9udW1lcmljKCkKCiMgVGhlc2UgYXJlIHRoZSBvbmVzIHRvIHVzZSBmb3IgY2x1c3RlcmluZyAKY2Vuc3VzX25vcm1lZAphZ2dfc3RhdGVfaW5mb19ub3JtZWQKYGBgCmBgYHtyfQojIFNhdmluZyB0byBjc3YgZm9yIGJldHRlciBsb2FkaW5nIGluIG90aGVyIGJyYW5jaGVzCndyaXRlX2NzdihjZW5zdXNfbm9ybWVkLCAiLi8uLi9kYXRhc2V0cy9jZW5zdXNfbm9ybWVkLmNzdiIpCndyaXRlX2NzdihhZ2dfc3RhdGVfaW5mb19ub3JtZWQsICIuLy4uL2RhdGFzZXRzL2FnZ19zdGF0ZV9pbmZvX25vcm1lZC5jc3YiKQpgYGAKCgpgYGB7cn0KIyBFeGFtcGxlIHVzZSB0byBnZXQgVFggc3BlY2lmaWNhbGx5CmtzID0gMjo0CldTUyA8LSBzYXBwbHkoa3MsIEZVTiA9IGZ1bmN0aW9uKGspIHsKICBrbWVhbnMoY2Vuc3VzX25vcm1lZCAlPiUgZmlsdGVyKHN0YXRlPT0iVFgiKSAKICAgICAgICAgJT4lIHNlbGVjdF9pZihpcy5kb3VibGUpLCBjZW50ZXJzID0gaywgbnN0YXJ0ID0gNSkkdG90LndpdGhpbnNzCiAgfSkKCmdncGxvdChhc190aWJibGUoa3MsIFdTUyksIGFlcyhrcywgV1NTKSkgKyBnZW9tX2xpbmUoKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gNCwgY29sb3IgPSAicmVkIiwgbGluZXR5cGUgPSAyKQpgYGAKYGBge3J9CiMgRXhhbXBsZSB1c2luZyBhZ2dyZWdhdGVkIHN0YXRlIGRhdGEKa3MgPSAyOjQKV1NTIDwtIHNhcHBseShrcywgRlVOID0gZnVuY3Rpb24oaykgewogIGttZWFucyhhZ2dfc3RhdGVfaW5mb19ub3JtZWQgICU+JSBzZWxlY3RfaWYoaXMuZG91YmxlKSwKICAgICAgICAgY2VudGVycyA9IGssIG5zdGFydCA9IDUpJHRvdC53aXRoaW5zcwogIH0pCgpnZ3Bsb3QoYXNfdGliYmxlKGtzLCBXU1MpLCBhZXMoa3MsIFdTUykpICsgZ2VvbV9saW5lKCkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDQsIGNvbG9yID0gInJlZCIsIGxpbmV0eXBlID0gMikKYGBgCgoK